package wiki.xsx.jg.core;

import wiki.xsx.jg.annotation.Id;
import wiki.xsx.jg.annotation.Ignore;
import wiki.xsx.jg.annotation.IsNotNull;

import java.io.File;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 数据表生成器
 */
public class TableGenerator {

    /**
     * 生成数据表
     * @param classNames 类名，多个逗号分隔
     * @param driverClassName 数据库驱动名称
     * @param dbUrl 数据库地址
     * @param userName 数据库用户名
     * @param password 数据库密码
     * @param rootPath 包的根路径
     * @param packageName 完整包名，如com.xsx.test
     * @throws Exception
     */
    public static void run(
            String classNames,
            String driverClassName,
            String dbUrl,
            String userName,
            String password,
            String rootPath,
            String packageName
    ) throws Exception{
        DatabaseService service = DatabaseAdapter.getServiceInstance(driverClassName, dbUrl, userName, password);
        List<String> classNameList = getClassNameList(classNames, rootPath, packageName);
        Map<String, Map<String, List<Map<String, Class<?>>>>> classInfoMap = getClassInfo(classNameList);
        service.createTables(classInfoMap);
    }

    /**
     * 根据类名称或包获取完整类名称集合
     * @param classNames 类名称，多个逗号分隔
     * @param rootPath 包的根路径
     * @param packageName 完整包名，如com.xsx.test
     * @return 返回完整类名集合
     * @throws Exception
     */
    private static List<String> getClassNameList(String classNames, String rootPath, String packageName) throws Exception{
        List<String> list = new ArrayList<>();
        if (classNames!=null&&classNames.trim().length()>0){
            String names[] = classNames.split(",");
            for (String name : names){
                StringBuilder classNameBuilder = new StringBuilder(packageName);
                classNameBuilder.append(".").append(name);
                list.add(classNameBuilder.toString());
            }
        }else{
            StringBuilder pathBuilder = new StringBuilder(rootPath);
            String dirs[] = packageName.split("\\.");
            for (String dir : dirs){
                pathBuilder.append(File.separator).append(dir);
            }
            File fileDir = new File(pathBuilder.toString());
            if (fileDir.isDirectory()){
                String names[] = fileDir.list();
                for (String name : names){
                    if (name.endsWith(".java")){
                        StringBuilder classNameBuilder = new StringBuilder(packageName);
                        classNameBuilder.append(".").append(name.substring(0, name.lastIndexOf(".java")));
                        list.add(classNameBuilder.toString());
                    }
                }
            }
        }
        return list;
    }

    /**
     * 根据完整类名称获取类的所有属性及属性类型
     * @param classNameList 完整类名称
     * @return 返回类的所有属性及属性类型集合
     * @throws Exception
     */
    private static Map<String, Map<String, List<Map<String, Class<?>>>>> getClassInfo(List<String> classNameList) throws Exception{
        Map<String, Map<String, List<Map<String, Class<?>>>>> classMap = new HashMap<>();
        for (String className : classNameList){
            Map<String, List<Map<String, Class<?>>>> fieldMap = new HashMap<>();
            List<Map<String, Class<?>>> primaryList = new ArrayList<>();
            List<Map<String, Class<?>>> isNotNullList = new ArrayList<>();
            List<Map<String, Class<?>>> isNullList = new ArrayList<>();
            Class<?> tempClass = Class.forName(className);
            if (tempClass.getAnnotation(Ignore.class)!=null){
                continue;
            }
            while (tempClass!=null&&!tempClass.getName().equalsIgnoreCase("java.lang.object")){
                Field fields[] = tempClass.getDeclaredFields();
                for (Field field : fields){
                    Map<String, Class<?>> data = new HashMap<>();
                    Ignore ignore = field.getAnnotation(Ignore.class);
                    if (ignore==null){
                        data.put(field.getName(), field.getType());
                        Id id = field.getAnnotation(Id.class);
                        if (id!=null){
                            primaryList.add(data);
                        }else{
                            IsNotNull isNotNull = field.getAnnotation(IsNotNull.class);
                            if (isNotNull!=null){
                                isNotNullList.add(data);
                            }else{
                                isNullList.add(data);
                            }
                        }
                    }
                }
                tempClass = tempClass.getSuperclass();
            }
            fieldMap.put("primary", primaryList);
            fieldMap.put("isNull", isNullList);
            fieldMap.put("isNotNull", isNotNullList);
            classMap.put(className.substring(className.lastIndexOf(".")+1).toLowerCase(), fieldMap);
        }
        return classMap;
    }
}
